package com.gzhryc.shared_device.oem.code.member.services;

import com.gzhryc.common.config.DefaultEnum;
import com.gzhryc.common.exceptions.LogicException;
import com.gzhryc.common.logging.Logger;
import com.gzhryc.jdbc.Conditions;
import com.gzhryc.jdbc.JdbcSession;
import com.gzhryc.jdbc.MultiDBTools;
import com.gzhryc.shared_device.base.IMemberWalletService;
import com.gzhryc.shared_device.base.enums.WalletOperateEnum;
import com.gzhryc.shared_device.base.models.OperateInfo;
import com.gzhryc.shared_device.oem.code.member.dao.MemberWalletDao;
import com.gzhryc.shared_device.oem.code.member.dao.db.MemberWallet;

import java.sql.SQLException;
import java.util.Date;

public class MemberWalletService implements IMemberWalletService {

	static Logger log = Logger.getLogger(MemberWalletService.class);

	public static MemberWalletService self() {
		return MultiDBTools.getService(MemberWalletService.class, true);
	}

	public static MemberWalletService self(String jdbcKey) {
		return MultiDBTools.getService(jdbcKey, MemberWalletService.class, true);
	}

	private String jdbcKey;

	public MemberWalletService(String jdbcKey) {
		this.jdbcKey = jdbcKey;
	}

	public MemberWallet getByMemberId(Long memberId) {
		if (memberId != null) {
			MemberWalletDao dao = new MemberWalletDao(jdbcKey,memberId);
			try {
				return dao.getById(memberId);
			} catch (SQLException e) {
				log.error(e.getMessage(), e);
			}
		}
		return null;
	}

	public Long sumMoney() {
		Long money = 0L;
		try {
			for (long i = 1l; i <= 9L; i++) {
				MemberWalletDao dao = new MemberWalletDao(jdbcKey, i);
				Long temp = dao.sumMoneyByConditions(new Conditions());
				if(temp != null) {
					money = money + temp;
				}
			}
		} catch (SQLException e) {
			log.error(e.getMessage(), e);
		}
		return money;
	}

	public boolean addDefaultWallet(Long memberId) {
		MemberWallet wallet = this.getByMemberId(memberId);
		if (wallet != null) {
			return true;
		} else {
			wallet = new MemberWallet();
			wallet.setMemberId(memberId);
			wallet.setCreateDate(new Date());

			MemberWalletDao dao = new MemberWalletDao(jdbcKey,memberId);
			try {
				return dao.insert(wallet) > 0;
			} catch (SQLException e) {
				log.error(e.getMessage(), e);
			}
		}

		return false;
	}

	public boolean hasMoney(Long memberId,Long money){
		if(memberId != null && money != null){
			Conditions condition = new Conditions(MemberWallet.class);
			condition.and().is("memberId", memberId);
			condition.and().ge("money", money);
			condition.and().is("state", DefaultEnum.Status.Usable.index());

			MemberWalletDao dao = new MemberWalletDao(jdbcKey,memberId);
			try {
				return dao.count(condition) > 0;
			} catch (SQLException e) {
				log.error(e.getMessage(),e);
			}
		}
		return false;
	}

	public boolean hasVMoney(Long memberId,Long virtualMoney){
		if(memberId != null && virtualMoney != null){
			Conditions condition = new Conditions(MemberWallet.class);
			condition.and().is("memberId", memberId);
			condition.and().ge("virtualMoney", virtualMoney);
			condition.and().is("state", DefaultEnum.Status.Usable.index());

			MemberWalletDao dao = new MemberWalletDao(jdbcKey,memberId);
			try {
				return dao.count(condition) > 0;
			} catch (SQLException e) {
				log.error(e.getMessage(),e);
			}
		}
		return false;
	}

	public synchronized boolean addFreezeMoney(Long memberId, Long freezeMoney, OperateInfo operateInfo) {
		MemberWallet wallet = getByMemberId(memberId);
		if(wallet != null){
			Date currentDate = new Date();
			
			Conditions condition = new Conditions(MemberWallet.class);
			condition.and().is("memberId", memberId);
			condition.and().is("freezeMoney", wallet.getFreezeMoney());
			condition.and().is("state", DefaultEnum.Status.Usable.index());
			condition.and().is("lastUpdateDate", wallet.getLastUpdateDate());

			MemberWallet walletUpdate = new MemberWallet();
			walletUpdate.setFreezeMoney(wallet.getFreezeMoney() + freezeMoney);
			walletUpdate.setLastUpdateDate(currentDate);

			MemberWalletDao dao = new MemberWalletDao(jdbcKey,memberId);
			try {
				if (dao.updateNotNull(walletUpdate, condition) > 0) {
					MemberWalletOperateService.self(jdbcKey,currentDate).addOperate(wallet.getMemberId(), WalletOperateEnum.MoneyType.FreezeMoney.index(),
							WalletOperateEnum.Type.Add.index(), freezeMoney, operateInfo);
					return true;
				}
			} catch (SQLException e) {
				log.error(e.getMessage(), e);
			}
		}
		return false;
	}

	/**
	 * 检查冻结金额
	 */
	public synchronized boolean reduceFreezeMoney(Long memberId, Long freezeMoney, OperateInfo operateInfo)
			throws LogicException {
		MemberWallet wallet = getByMemberId(memberId);
		if(wallet != null) {
			// 检查是否够提现金额
			Long surplusMoney = wallet.getFreezeMoney() - freezeMoney;
			if (surplusMoney < 0) {
				throw new LogicException("超过冻结余额");
			} else {
				Date currentDate = new Date();
				
				Conditions condition = new Conditions(MemberWallet.class);
				condition.and().is("memberId", memberId);
				condition.and().is("freezeMoney", wallet.getFreezeMoney());
				condition.and().is("state", DefaultEnum.Status.Usable.index());
				condition.and().is("lastUpdateDate", wallet.getLastUpdateDate());

				MemberWallet walletUpdate = new MemberWallet();
				walletUpdate.setFreezeMoney(surplusMoney);
				walletUpdate.setLastUpdateDate(currentDate);

				MemberWalletDao dao = new MemberWalletDao(jdbcKey,memberId);
				try {
					if (dao.updateNotNull(walletUpdate, condition) > 0) {
						MemberWalletOperateService.self(jdbcKey,currentDate).addOperate(wallet.getMemberId(), WalletOperateEnum.MoneyType.FreezeMoney.index(),
								WalletOperateEnum.Type.Reduce.index(), freezeMoney, operateInfo);
						return true;
					}
				} catch (SQLException e) {
					log.error(e.getMessage(), e);
				}
			}
		}
		return false;
	}

	public synchronized boolean freezeMoney(Long memberId, Long money, OperateInfo operateInfo) throws LogicException {
		MemberWallet wallet = getByMemberId(memberId);
		if (wallet != null) {
			// 检查是否够提现金额
			Long surplusMoney = wallet.getMoney() - money;
			if (surplusMoney < 0) {
				throw new LogicException("超过钱包余额");
			} else {
				Date currentDate = new Date();
				
				Conditions condition = new Conditions(MemberWallet.class);
				condition.and().is("memberId", memberId);
				condition.and().is("money", wallet.getMoney());
				condition.and().is("freezeMoney", wallet.getFreezeMoney());
				condition.and().is("lastUpdateDate", wallet.getLastUpdateDate());

				MemberWallet walletUpdate = new MemberWallet();
				walletUpdate.setMoney(surplusMoney);
				walletUpdate.setFreezeMoney(wallet.getFreezeMoney() + money);
				walletUpdate.setLastUpdateDate(currentDate);

				MemberWalletDao dao = new MemberWalletDao(jdbcKey,memberId);
				try {
					if (dao.updateNotNull(walletUpdate, condition) > 0) {
						MemberWalletOperateService.self(jdbcKey,currentDate).addOperate(wallet.getMemberId(), WalletOperateEnum.MoneyType.Money.index(),
								WalletOperateEnum.Type.Reduce.index(), money, operateInfo);
						MemberWalletOperateService.self(jdbcKey,currentDate).addOperate(wallet.getMemberId(), WalletOperateEnum.MoneyType.FreezeMoney.index(),
								WalletOperateEnum.Type.Add.index(), money, operateInfo);
						return true;
					}
				} catch (SQLException e) {
					log.error(e.getMessage(), e);
				}
			}
		}
		return false;
	}

	public synchronized boolean unfreezeAndReduceMoney(Long memberId, Long unfreezeMoney, Long money, OperateInfo operateInfo) throws LogicException {
		MemberWallet wallet = getByMemberId(memberId);
		if (wallet != null) {
			// 检查是否够提现金额
			Long surplusMoney = wallet.getFreezeMoney() - unfreezeMoney - money;
			if (surplusMoney < 0) {
				throw new LogicException("超过冻结余额");
			} else {
				Date currentDate = new Date();
				
				Conditions condition = new Conditions(MemberWallet.class);
				condition.and().is("memberId", memberId);
				condition.and().is("money", wallet.getMoney());
				condition.and().is("freezeMoney", wallet.getFreezeMoney());
				condition.and().is("lastUpdateDate", wallet.getLastUpdateDate());

				MemberWallet walletUpdate = new MemberWallet();
				walletUpdate.setMoney(wallet.getMoney() + unfreezeMoney); // 增加余额
				walletUpdate.setFreezeMoney(surplusMoney);
				walletUpdate.setLastUpdateDate(new Date());

				MemberWalletDao dao = new MemberWalletDao(jdbcKey,memberId);
				try {
					if (dao.updateNotNull(walletUpdate, condition) > 0) {
						MemberWalletOperateService.self(jdbcKey,currentDate).addOperate(wallet.getMemberId(), WalletOperateEnum.MoneyType.Money.index(),
								WalletOperateEnum.Type.Add.index(), unfreezeMoney, operateInfo);
						MemberWalletOperateService.self(jdbcKey,currentDate).addOperate(wallet.getMemberId(), WalletOperateEnum.MoneyType.FreezeMoney.index(),
								WalletOperateEnum.Type.Reduce.index(), (money + unfreezeMoney), operateInfo);
						return true;
					}
				} catch (SQLException e) {
					log.error(e.getMessage(), e);
				}
			}
		}
		return false;
	}

	public synchronized boolean unfreezeMoney(Long memberId, Long money, OperateInfo operateInfo) throws LogicException {
		MemberWallet wallet = getByMemberId(memberId);
		if (wallet != null) {
			// 检查是否够提现金额
			Long surplusMoney = wallet.getFreezeMoney() - money;
			if (surplusMoney < 0) {
				throw new LogicException("超过冻结余额");
			} else {
				Date currentDate = new Date();
				
				Conditions condition = new Conditions(MemberWallet.class);
				condition.and().is("memberId", memberId);
				condition.and().is("money", wallet.getMoney());
				condition.and().is("freezeMoney", wallet.getFreezeMoney());
				condition.and().is("state", DefaultEnum.Status.Usable.index());
				condition.and().is("lastUpdateDate", wallet.getLastUpdateDate());

				MemberWallet walletUpdate = new MemberWallet();
				walletUpdate.setMoney(wallet.getMoney() + money); // 增加余额
				walletUpdate.setFreezeMoney(surplusMoney);
				walletUpdate.setLastUpdateDate(currentDate);

				MemberWalletDao dao = new MemberWalletDao(jdbcKey,memberId);
				try {
					if (dao.updateNotNull(walletUpdate, condition) > 0) {
						MemberWalletOperateService.self(jdbcKey,currentDate).addOperate(wallet.getMemberId(), WalletOperateEnum.MoneyType.Money.index(),
								WalletOperateEnum.Type.Add.index(), money, operateInfo);
						MemberWalletOperateService.self(jdbcKey,currentDate).addOperate(wallet.getMemberId(), WalletOperateEnum.MoneyType.FreezeMoney.index(),
								WalletOperateEnum.Type.Reduce.index(), money, operateInfo);
						return true;
					}
				} catch (SQLException e) {
					log.error(e.getMessage(), e);
				}
			}
		}
		return false;
	}

	/**
	 * 检查钱包余额
	 */
	public synchronized boolean reduceMoney(Long memberId, Long money, OperateInfo operateInfo) throws LogicException {
		MemberWallet wallet = this.getByMemberId(memberId);
		if (wallet == null) {
			throw new LogicException("钱包未启用");
		}
		// 检查金额是否够扣除
		if (wallet.getMoney() < money) {
			throw new LogicException("会员余额不足");
		}else{
			Date currentDate = new Date();
			
			Conditions condition = new Conditions(MemberWallet.class);
			condition.and().is("memberId", memberId);
			condition.and().is("money", wallet.getMoney());
			condition.and().is("state", DefaultEnum.Status.Usable.index());
			condition.and().is("lastUpdateDate", wallet.getLastUpdateDate());

			MemberWallet walletUpdate = new MemberWallet();
			walletUpdate.setMoney(wallet.getMoney() - money);
			walletUpdate.setLastUpdateDate(currentDate);

			MemberWalletDao dao = new MemberWalletDao(jdbcKey,memberId);
			try {
				if (dao.updateNotNull(walletUpdate, condition) > 0) {
					MemberWalletOperateService.self(jdbcKey,currentDate).addOperate(wallet.getMemberId(), WalletOperateEnum.MoneyType.Money.index(),
							WalletOperateEnum.Type.Reduce.index(), money,operateInfo);
					return true;
				}
			} catch (SQLException e) {
				log.error(e.getMessage(), e);
			}
		}
		return false;
	}

	/**
	 * 如果钱包金额不足， 强制减少钱包剩余余额
	 * @param memberId
	 * @param money
	 * @param operateInfo
	 * @return	减少的金额
	 * @throws LogicException
	 */
	public synchronized Long reduceFaceMoney(Long memberId,Long money,OperateInfo operateInfo) throws LogicException {
		MemberWallet wallet = this.getByMemberId(memberId);
		if (wallet == null) {
			throw new LogicException("钱包未启用");
		}
		Long walletMoney = money;
		// 检查金额是否够扣除
		if (wallet.getMoney() < money) {
			walletMoney = money - wallet.getMoney();
		}
		
		if(walletMoney > 0){
			Date currentDate = new Date();
			
			Conditions condition = new Conditions(MemberWallet.class);
			condition.and().is("memberId", memberId);
			condition.and().is("money", wallet.getMoney());
			condition.and().is("state", DefaultEnum.Status.Usable.index());
			condition.and().is("lastUpdateDate", wallet.getLastUpdateDate());

			MemberWallet walletUpdate = new MemberWallet();
			walletUpdate.setMoney(wallet.getMoney() - walletMoney);
			walletUpdate.setLastUpdateDate(currentDate);

			MemberWalletDao dao = new MemberWalletDao(jdbcKey,memberId);
			try {
				if (dao.updateNotNull(walletUpdate, condition) > 0) {
					MemberWalletOperateService.self(jdbcKey,currentDate).addOperate(wallet.getMemberId(), WalletOperateEnum.MoneyType.Money.index(),
							WalletOperateEnum.Type.Reduce.index(), walletMoney,operateInfo);
					return walletMoney;
				}
			} catch (SQLException e) {
				log.error(e.getMessage(), e);
			}
		}
		return 0L;
	}
	
	public synchronized boolean addMoney(Long memberId, Long money, OperateInfo operateInfo) throws LogicException {
		MemberWallet wallet = this.getByMemberId(memberId);
		if (wallet == null) {
			throw new LogicException("钱包未启用");
		}
		Date currentDate = new Date();

		Conditions condition = new Conditions(MemberWallet.class);
		condition.and().is("memberId", memberId);
		condition.and().is("money", wallet.getMoney());
		condition.and().is("state", DefaultEnum.Status.Usable.index());
		condition.and().is("lastUpdateDate", wallet.getLastUpdateDate());

		MemberWallet walletUpdate = new MemberWallet();
		walletUpdate.setMoney(wallet.getMoney() + money);
		walletUpdate.setLastUpdateDate(currentDate);

		MemberWalletDao dao = new MemberWalletDao(jdbcKey,memberId);
		try {
			if (dao.updateNotNull(walletUpdate, condition) > 0) {
				MemberWalletOperateService.self(jdbcKey,currentDate).addOperate(wallet.getMemberId(), WalletOperateEnum.MoneyType.Money.index(),
						WalletOperateEnum.Type.Add.index(), money,operateInfo);
				return true;
			}
		} catch (SQLException e) {
			log.error(e.getMessage(), e);
		}
		return false;
	}

	public synchronized boolean reduceVMoney(Long memberId, Long money, OperateInfo operateInfo) throws LogicException {
		MemberWallet wallet = this.getByMemberId(memberId);
		if (wallet == null) {
			throw new LogicException("钱包未启用");
		}
		// 检查金额是否够扣除
		if (wallet.getVirtualMoney() >= money) {
			Date currentDate = new Date();
			
			Conditions condition = new Conditions(MemberWallet.class);
			condition.and().is("memberId", memberId);
			condition.and().is("virtualMoney", wallet.getVirtualMoney());
			condition.and().is("state", DefaultEnum.Status.Usable.index());
			condition.and().is("lastUpdateVmDate", wallet.getLastUpdateVmDate());

			MemberWallet walletUpdate = new MemberWallet();
			walletUpdate.setVirtualMoney(wallet.getVirtualMoney() - money);
			walletUpdate.setLastUpdateVmDate(currentDate);

			MemberWalletDao dao = new MemberWalletDao(jdbcKey,memberId);
			try {
				if (dao.updateNotNull(walletUpdate, condition) > 0) {
					MemberWalletOperateService.self(jdbcKey,currentDate).addOperate(wallet.getMemberId(), WalletOperateEnum.MoneyType.VirtualMoney.index(),
							WalletOperateEnum.Type.Reduce.index(), money,operateInfo);
					return true;
				}
			} catch (SQLException e) {
				log.error(e.getMessage(), e);
			}
		}
		return false;
	}

	/**
	 * 增加虚拟货币
	 *
	 * @param memberId
	 * @param money
	 * @return
	 * @throws LogicException
	 */
	public synchronized boolean addVMoney(Long memberId, Long money, OperateInfo operateInfo) throws LogicException {
		MemberWallet wallet = this.getByMemberId(memberId);
		if (wallet == null) {
			throw new LogicException("钱包未启用");
		}
		Date currentDate = new Date();

		Conditions condition = new Conditions(MemberWallet.class);
		condition.and().is("memberId", memberId);
		condition.and().is("virtualMoney", wallet.getVirtualMoney());
		condition.and().is("state", DefaultEnum.Status.Usable.index());
		condition.and().is("lastUpdateVmDate", wallet.getLastUpdateVmDate());

		MemberWallet walletUpdate = new MemberWallet();
		walletUpdate.setVirtualMoney(wallet.getVirtualMoney() + money);
		walletUpdate.setLastUpdateVmDate(currentDate);

		MemberWalletDao dao = new MemberWalletDao(jdbcKey,memberId);
		try {
			if (dao.updateNotNull(walletUpdate, condition) > 0) {
				MemberWalletOperateService.self(jdbcKey,currentDate).addOperate(wallet.getMemberId(), WalletOperateEnum.MoneyType.VirtualMoney.index(),
						WalletOperateEnum.Type.Add.index(), money, operateInfo);
				return true;
			}
		} catch (SQLException e) {
			log.error(e.getMessage(), e);
		}
		return false;
	}

	
	public boolean updateMoney(Long memberId, Integer type, Long money, OperateInfo operateInfo) throws LogicException {
		MemberWallet wallet = this.getByMemberId(memberId);
		if (wallet == null) {
			throw new LogicException("钱包未启用");
		}

		if (WalletOperateEnum.Type.Add.index().equals(type)) {
			return addMoney(memberId, money, operateInfo);
		} else if (WalletOperateEnum.Type.Reduce.index().equals(type)) {
			return reduceMoney(memberId, money, operateInfo);
		}
		return false;
	}

	
	public boolean deleteByMemberId(Long memberId){
		if(memberId != null) {
			MemberWalletDao dao = new MemberWalletDao(jdbcKey,memberId);
			JdbcSession.begin();
			try {
				if (dao.deleteById(memberId) >= 0) {
					if (MemberWalletOperateService.self(jdbcKey,new Date()).deleteByMemberId(memberId)) {
						JdbcSession.commit();
						return true;
					}
				}
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				JdbcSession.end();
			}
		}
		return false;
	}
}
